package top.bulk.intemasking.serializer;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import top.bulk.intemasking.annotation.SensitiveMasking;
import top.bulk.intemasking.enums.SensitiveTypeEnum;

import java.io.IOException;

/**
 * 敏感词处理
 *
 * @author 散装java
 * @date 2024-07-15
 */
public class SensitiveSerializer extends JsonSerializer<String> implements ContextualSerializer {
    /**
     * 脱敏类型，默认为DEFAULT
     */
    private SensitiveTypeEnum type;
    /**
     * 脱敏起始位置
     */
    private int startInclude;
    /**
     * 脱敏结束位置
     */
    private int endExclude;

    private char replacedChar;

    /**
     * 序列化字符串时调用，根据脱敏类型对字符串进行相应的脱敏处理。
     *
     * @param value       待序列化的字符串
     * @param gen         JSON生成器，用于写入处理后的字符串
     * @param serializers 序列化器提供者，用于获取其他序列化器
     * @throws IOException 如果序列化过程中发生I/O错误
     */
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 脱敏
        gen.writeString(type.hide(value, startInclude, endExclude, replacedChar));
    }

    /**
     * 根据上下文信息创建自定义的序列化器，用于处理带有@Desensitize注解的属性。
     *
     * @param prov     序列化器提供者，用于获取其他序列化器
     * @param property 当前属性的信息，用于获取注解和属性类型
     * @return 自定义的序列化器实例
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        if (property != null) {
            SensitiveMasking annotation = property.getAnnotation(SensitiveMasking.class);
            if (annotation != null) {
                this.type = annotation.type();
                // 如果是自定义脱敏
                if (annotation.type() == SensitiveTypeEnum.CUSTOM_RULE) {
                    this.startInclude = annotation.startInclude();
                    this.endExclude = annotation.endExclude();
                    this.replacedChar = annotation.replacedChar();
                }
            }
        }
        return this;
    }

}
